#define _CRT_SECURE_NO_WARNINGS  //scanf()的报错4996,必须放在最开头
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

//  1. 多级指针
int a = 1;
int* p = &a;
int** pp = &p;
int*** ppp = &pp;
/*
            *作用关系
        *ppp == pp == &p
        **ppp == *pp == p == &a
        ***ppp == **pp == *p ==a
*/

//-----------------------------
//  2. 结构体指针
struct st{
    int a1;     //32位X86系统，指针都占4字节
    char* a2;   //字符串常量，用strcpy(sp.a2, "字符串")进行赋值
};
//      2.1 单元素
struct st* sp = (struct st*)malloc(sizeof(struct st));
if (sp == NULL) {
    printf("%s\n", "内存开辟失败");
    return -1;
}
sp->a2 = (char*)malloc(sizeof(char) * 50); //字符串常量开辟空间

sp->a1 = 10;
printf("%d\n", sp->a1);
printf("%p\n", &(sp->a1)); //查看地址

strcpy(sp->a2, "aaa");
printf("%s\n", sp->a2);
printf("%p\n", &(sp->a2));
system("pause");

free(sp->a2);
free(sp);       // 用完就释放
sp = NULL;    // 释放后是野指针，可以手动指向空指针，指向空指针的好处是多次free释放不会报错，野指针不能多次free

//      2.2 多元素数组
struct st* sp = (struct st*)malloc(sizeof(struct st)*3);
if (sp == NULL) {
    printf("%s\n", "内存开辟失败");
    return -1;
}
/*printf("size: %d\n", sizeof(sp));
printf("size: %d\n", sizeof(sp[0]));
printf("%p\n", &sp[0]);
printf("%p\n", &sp[1]);
printf("%p\n", &sp[2]);*/
sp[0].a1 = 10;
//sp[0].a2 = "aaa"; //这是常量赋值，不需要开辟空间，但，一旦赋值了就不能再次修改
sp[0].a2 = (char*)malloc(sizeof(char) * 20);
strcpy(sp[0].a2, "aaa");  //需要开辟空间后才能用
printf("%s\n", sp[0].a2);

/*
    结构体内部指针好处：占字节大小都是指针大小，容易内存对齐，不会占用太多栈内存。
*/
